#include "abstract-database-client.h"
#include "model-result.h"
#include "order-item-section-model.h"
#include "order-item-section-queries.h"
#include "spin-box-delegate.h"
#include "standard-table-model.h"
#include "value-result.h"

#include "line-edit-delegate.h"

OrderItemSectionModel::OrderItemSectionModel(QObject *parent) :
    StandardDatabaseModel(parent)
{
    m_idColumnCount = 4;
}

void OrderItemSectionModel::initialize()
{
    m_queries = new OrderItemSectionQueries(this);
    SpinBoxDelegate* quantityDelegate = new SpinBoxDelegate(this);
    quantityDelegate->setRange(1, 1000000);
    m_delegates.insert(QuantityColumn, quantityDelegate);
    m_headerSections << "Nazwa" << "Cena" << "VAT" << "Ilość";
    m_dataAlreadyExistText = "Pozycja o takich danych już istnieje.";

    StandardDatabaseModel::initialize();
}

void OrderItemSectionModel::setupInternalModel()
{
    StandardDatabaseModel::setupInternalModel();

    StandardTableModel* internalModel = qobject_cast<StandardTableModel*>(m_internalModel);
    internalModel->swapColumns(NameColumn+m_idColumnCount, VatColumn+m_idColumnCount);
    internalModel->swapColumns(QuantityColumn+m_idColumnCount, PriceColumn+m_idColumnCount);
}

void OrderItemSectionModel::addData (QVariantList dataList)
{
    ValueResult* result = m_databaseClient->insertData(m_queries->insertQuery(0, dataList.size()/7), dataList);
    connect (result, &ValueResult::resultReady, this, &OrderItemSectionModel::finishAddData);
}

void OrderItemSectionModel::finishAddData (ValueResult* result)
{
    result->deleteLater();
    if (result->hasError())
    {
        emit notifyWarning("Błąd dodawania danych.", result->error().text());
        emit addDataFinished(false);
        return;
    }

    connect (this, &OrderItemSectionModel::loadDataFinished, this, &OrderItemSectionModel::updateOrderSum);
    loadData();
    emit addDataFinished(true);
}

ValueResult* OrderItemSectionModel::canSetField (QVariant value, int column, int row)
{
    Q_UNUSED(value);
    Q_UNUSED(column);
    Q_UNUSED(row);
    ValueResult* result = new ValueResult(this);
    result->setValue(true);
    return result;
}

ValueResult* OrderItemSectionModel::canSetRow (QVariantList dataList, int row)
{
    Q_UNUSED(dataList);
    Q_UNUSED(row);
    ValueResult* result = new ValueResult(this);
    result->setValue(true);
    return result;
}

void OrderItemSectionModel::updateData (QVariant data, int row, int column)
{
    Q_UNUSED(column);
    QVariantList dataList;
    dataList << id(row, 0) << id(row, 1) << id(row, 2) << id(row, 3)
             << index(row, VatColumn).data(Qt::UserRole)
             << data
             << index(row, NameColumn).data(Qt::UserRole)
             << index(row, PriceColumn).data(Qt::UserRole);

    ValueResult* result = m_databaseClient->updateData(m_queries->updateQuery(0, 0), dataList);
    connect (result, &ValueResult::resultReady, this, &OrderItemSectionModel::finishUpdateData);
}

void OrderItemSectionModel::finishUpdateData (ValueResult* result)
{
    result->deleteLater();
    if (result->hasError())
    {
        emit notifyWarning("Błąd edycji danych", result->error().text());
        emit updateDataFinished(false);
        return;
    }

    connect (this, &OrderItemSectionModel::loadDataFinished, this, &OrderItemSectionModel::updateOrderSum);
    loadData();
    emit updateDataFinished(true);
}

void OrderItemSectionModel::finishRemoveData (ValueResult* result)
{
    result->deleteLater();
    if (result->hasError())
    {
        emit notifyWarning("Błąd usuwania danych", result->error().text());
        emit removeDataFinished(false);
        return;
    }

    connect (this, &OrderItemSectionModel::loadDataFinished, this, &OrderItemSectionModel::updateOrderSum);
    loadData();
    emit removeDataFinished(true);
}

void OrderItemSectionModel::updateOrderSum (bool dataLoaded)
{
    disconnect (this, &OrderItemSectionModel::loadDataFinished, this, &OrderItemSectionModel::updateOrderSum);
    if (!dataLoaded)
    {
        emit notifyWarning("Błąd edycji danych", "Nie udało się zaktualizować sumy zamówienia.");
        return;
    }

    ModelResult* result = m_databaseClient->selectModel(m_queries->selectQuery(1, 0), m_loadingParameters.at(0));
    connect (result, &ModelResult::resultReady, this, &OrderItemSectionModel::continueUpdateOrderSum);
}

void OrderItemSectionModel::continueUpdateOrderSum (ModelResult* result)
{
    result->deleteLater();
    if (result->hasError())
    {
        emit notifyWarning("Błąd edycji danych", result->error().text());
        return;
    }

    float sum = 0;
    for (int i = 0; i < rowCount(); i++)
    {
        sum += index(i, PriceColumn).data(Qt::UserRole).toFloat() * index(i, QuantityColumn).data(Qt::UserRole).toFloat()
                * (1 + index(i, VatColumn).data(Qt::UserRole).toFloat()/100.0);
    }

    QAbstractTableModel* model = result->model();
    QVariantList dataList;
    for (int i = 0; i < model->columnCount()-1; i++)
        dataList << model->index(0, i).data();
    dataList << sum;

    ValueResult* newResult = m_databaseClient->updateData(m_queries->updateQuery(1, 0), dataList);
    connect (newResult, &ValueResult::resultReady, this, &OrderItemSectionModel::finishUpdateOrderSum);
}

void OrderItemSectionModel::finishUpdateOrderSum (ValueResult* result)
{
    result->deleteLater();
    if (result->hasError())
    {
        emit notifyWarning("Błąd edycji danych", result->error().text());
        return;
    }
}

Qt::ItemFlags OrderItemSectionModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::NoItemFlags;

    if (index.column() == QuantityColumn && m_isEditingCurrentlyEnabled)
        return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    else
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
